/*
 * GestureAcquisitionView.java
 *
 * Author: Kyle Fernald
 * Created: 2-16-2010
 * EE464K Senior Design - University of Texas
 */

package gestureacquisition;

import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import org.jdesktop.application.Action;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import jserialport.JserialPort;

public class GestureAcquisitionView extends FrameView {

    private static final String SERIAL_DLL_LOCATION = "C:/Users/Kyle/Documents/NetBeansProjects/JserialPort/src/jserialport";
    private static final int COM_PORT = 4;
    private static final String CAMERA_LOCATOR = "vfw://0";

    private GestureToPoint g2p;
    private GestureInterpretation gi;
    private JserialPort serialPort;

    private boolean running = false;

    public GestureAcquisitionView(SingleFrameApplication app) {
        super(app);
        initComponents();
        progressBar.setVisible(false);

        //Initialize the hardware components:
        System.out.println("Initializing...");
        g2p = new GestureToPoint();

        if(!gi.init() || !g2p.init(CAMERA_LOCATOR) || !initSerialPort()){
            shutdown();
            System.exit(0);
        }

        //Control the closing of the window:
        getFrame().addWindowListener(new WindowAdapter(){
            @Override
            public void windowClosing(WindowEvent e){
                shutdown();
            }
        });
        System.out.println("Starting...");
        start();
    }

    public void start(){
        final Thread positionThread = new Thread(new Runnable(){
            public void run() {
                System.out.println("\tStarting position thread.");
                Point p;
                g2p.start();
                ArrayList<Point> points;
                while(running){
                    if(g2p.areNewPoints()){
                        points = g2p.getPoints();
                        gi.updatePositions(points);
                        for(int x = 0; x < points.size(); x++){
                            p = points.get(x);
                            System.out.print(p.x+","+p.y+'\t');
                        }
                        System.out.println();
                    }
                }
            }
        });

        //Create a separate thread to grab the finger data:
        final Thread xbeeThread = new Thread(new Runnable(){
            public void run() {
                System.out.println("\tStarting XBee thread.");
                char comByte;
                while(running){
                    comByte = serialPort.getChar();
                    //If the char isn't a valid XBee frame (or time's out):
                    if(comByte != 0x7e){
                        GestureAcquisitionView.sleep(90);
                        continue;
                    }
                    //Ignore intermediate bytes in the frame:
                    for(int x = 0; x < 11; x++){
                        serialPort.getChar();
                    }
                    comByte = serialPort.getChar();
                    if(comByte == 0){
                        try {
                            positionThread.wait();
                        } catch (InterruptedException ex) {
                        }
                    } else {
                        positionThread.notify();
                    }
                    gi.updateButtons(comByte);
                    System.out.println("Finger data: 0x"+Integer.toHexString(comByte));
                }
                positionThread.notify();
            }
        });
        running = true;
        positionThread.start();
        xbeeThread.start();
    }

    public void shutdown(){
        System.out.println("Shutting down...");
        try{
            running = false;
            serialPort.closePort();
            g2p.close();
            gi.close();
        }
        catch(NullPointerException e){
        }
    }

    private boolean initSerialPort(){
        //Init the serial port:
        System.out.println("\tOpening COM"+COM_PORT+"...");
        serialPort = new JserialPort(null, SERIAL_DLL_LOCATION);
        if(!serialPort.openPort(COM_PORT)){
            GestureAcquisitionView.showErrorDialog("INITIALIZE FAILED","Failed to open COM "+COM_PORT+".",null);
            return false;
        }
        return true;
    }

    /**
     * Forces the current thread to sleep (pause) for the given amount of ms.
     * Catches, but does simply returns on the event of an interruption.
     * @param millis the number of milliseconds to sleep.
     */
    public static void sleep(long millis){
        try {
            Thread.sleep(millis);
        } catch (InterruptedException ex){
        }
    }

    public static void showErrorDialog(String title, String message, Exception e){
        if(e == null){
            JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
        }
        else{
            JOptionPane.showMessageDialog(null, message+"\n\nError: "+e.getMessage(), title, JOptionPane.ERROR_MESSAGE);
        }
    }

    @Action
    public void showAboutBox() {
        JFrame mainFrame = GestureAcquisitionApp.getApplication().getMainFrame();
        JDialog aboutBox = new GestureAcquisitionAboutBox(mainFrame);
        aboutBox.setLocationRelativeTo(mainFrame);
        GestureAcquisitionApp.getApplication().show(aboutBox);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();

        mainPanel.setName("mainPanel"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(gestureacquisition.GestureAcquisitionApp.class).getContext().getActionMap(GestureAcquisitionView.class, this);
        jButton1.setAction(actionMap.get("showCamera")); // NOI18N
        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(gestureacquisition.GestureAcquisitionApp.class).getContext().getResourceMap(GestureAcquisitionView.class);
        jButton1.setText(resourceMap.getString("jButton1.text")); // NOI18N
        jButton1.setName("jButton1"); // NOI18N

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jButton1)
                .addContainerGap(267, Short.MAX_VALUE))
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jButton1)
                .addContainerGap(220, Short.MAX_VALUE))
        );

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N

        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 230, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

    @Action
    public void showCamera() {
        g2p.showCamera();
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    // End of variables declaration//GEN-END:variables

}
